use tokio::net::UdpSocket;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};

use crate::components::enums::{NetworkCommand, NetworkEvent};

// UDP 异步任务
pub async fn udp_task(
    mut cmd_rx: UnboundedReceiver<NetworkCommand>,
    event_tx: UnboundedSender<NetworkEvent>,
) {
    let mut socket: Option<UdpSocket> = None;
    let mut buf = vec![0; 4096];

    loop {
        tokio::select! {
            // 1. 处理来自 UI 的命令
            Some(command) = cmd_rx.recv() => {
                match command {
                    NetworkCommand::Connect(addr) => {
                        socket = None; // 丢弃旧的 socket
                        match UdpSocket::bind("0.0.0.0:0").await {
                            Ok(sock) => {
                                if let Err(e) = sock.connect(addr).await {
                                    let _ = event_tx.send(NetworkEvent::Error(e.to_string()));
                                    continue;
                                }
                                socket = Some(sock);
                                let _ = event_tx.send(NetworkEvent::Connected);
                            }
                            Err(e) => {
                                let _ = event_tx.send(NetworkEvent::Error(e.to_string()));
                            }
                        }
                    },
                    NetworkCommand::Send(data) => {
                        if let Some(s) = socket.as_ref() {
                            if let Err(e) = s.send(&data).await {
                                let _ = event_tx.send(NetworkEvent::Error(e.to_string()));
                            }
                        }
                    },
                    NetworkCommand::Disconnect => {
                        if socket.is_some() {
                            socket = None;
                            let _ = event_tx.send(NetworkEvent::Disconnected);
                        }
                    }
                }
            },

            // 2. 如果 socket 已设置，则尝试接收数据
            result = async {
                socket.as_ref().unwrap().recv(&mut buf).await
            }, if socket.is_some() => {
                match result {
                    Ok(n) => {
                        let _ = event_tx.send(NetworkEvent::DataReceived(buf[..n].to_vec()));
                    },
                    Err(e) => {
                        let _ = event_tx.send(NetworkEvent::Error(e.to_string()));
                    }
                }
            }
        }
    }
}
